package core;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import model.Category;
import model.Item;

import org.jboss.annotation.ejb.LocalBinding;

import utils.Utils;

@Stateless
@LocalBinding(jndiBinding="local/NearbyServices")
public class NearbyServices implements NearbyServicesLocal{

    @PersistenceContext
    private EntityManager em;
    
    public List<Category> getCategories(Integer idCategory, Double latitude, Double longitude, Double radious){
    	List<Category> resultList = getCategoryChilds(idCategory);
    	List<Category> finalList;
    	
    	if(latitude != null && longitude != null && radious != null){
    		finalList = new ArrayList<Category>();
    		
    		for (Category category : resultList) {
    			if (hasItemsNearby(category, latitude, longitude, radious) 
    					|| getCategories(category.getIdCategory(), latitude, longitude, radious).size() > 0){
    				
    				finalList.add(category);
    			}
    		}    		
    		
    	}else{
    		finalList = resultList;
    	}

    	return finalList;
    }
    
    public List<Item> getItems(Integer idCategory, Double latitude, Double longitude, Double radious){
    	List<Item> resultList = getItemChilds(idCategory);
    	List<Item> finalList;
    	
    	if(latitude != null && longitude != null && radious != null){
    		finalList = new ArrayList<Item>();
    		
    		for (Item item : resultList) {
    			if(isNear(item.getLatitude(), item.getLongitude(), latitude, longitude, radious)){
    				finalList.add(item);
    			}
    		}    		
    		
    	}else{
    		finalList = resultList;
    	}

    	return finalList;
    }    

	private boolean hasItemsNearby(Category category, Double latitude, Double longitude, Double radious) {
		List<Item> items = getItemChilds(category.getIdCategory());
		boolean result = false;
		if(items != null){
			Iterator<Item> iterator = items.iterator();
			while(!result && iterator.hasNext()){
				Item item = iterator.next();
				result = isNear(item.getLatitude(), item.getLongitude(), latitude, longitude, radious);
			}
		}
		return result;
	}

	private boolean isNear(Double latitude, Double longitude, Double latitude2,
			Double longitude2, Double radious) {
		
		return Utils.distance(latitude, longitude, latitude2, longitude2) <= radious;
	}

	private List<Category> getCategoryChilds(Integer idCategory) {
		StringBuilder sb = new StringBuilder();
    	sb.append("select c ");
    	sb.append("from Category c ");
    	
    	if(idCategory != null){
    		sb.append("where c.parent.idCategory = :idCategory ");
    	}else{
    		sb.append("where c.parent is null ");
    	}
    	
    	sb.append("order by c.name");
    	
    	Query q = em.createQuery(sb.toString());
    	
    	if(idCategory != null){
    		q.setParameter("idCategory", idCategory);
    	}
    	
    	List<Category> resultList = q.getResultList();
		return resultList;
	}
	
	private List<Item> getItemChilds(Integer idCategory) {
		StringBuilder sb = new StringBuilder();
		sb.append("select distinct i ");
		sb.append("from Item i ");
		sb.append("join fetch i.categories c ");
		
		if(idCategory != null){
			sb.append("where c.idCategory = :idCategory ");	
		}
		
		sb.append("order by i.name");
		
		Query q = em.createQuery(sb.toString());
		
		if(idCategory != null){
			q.setParameter("idCategory", idCategory);
		}
			
		return q.getResultList();
	}
}
